package com.gitee.wsl.db.dsl

import com.gitee.wsl.db.dsl.func.FORMATFunction
import com.gitee.wsl.db.dsl.func.MIDFunction
import com.gitee.wsl.db.dsl.func.ROUNDFunction
import com.gitee.wsl.db.dsl.operation.QueryOperation
import com.gitee.wsl.db.dsl.query.QBFParameters
import kotlin.time.ExperimentalTime
import kotlin.time.Instant

class Select(var selectColumns: Array<Any>) {
    var isDistinct: Boolean = false
    lateinit var tables: Array<Table>
    var qbfParameters: QBFParameters? = null
    var queryOperation: QueryOperation = QueryOperation()
    lateinit var groups: Array<Any>
    var having: QBFParameters? = null

    var unionSelect: Select? = null
    var joins: MutableList<Join> = mutableListOf<Join>()

    fun distinct(): Select {
        this.isDistinct = true
        return this
    }

    fun from(vararg tables: String): Select {
        this.tables = Array(tables.size){i->
            Table(tables[i])}
        /*this.tables = arrayOfNulls(tables.size)
        for (i in tables.indices) this.tables[i] = Table(
            tables[i]
        )*/

        return this
    }

    fun from(vararg tables: Table): Select {
        this.tables = arrayOf(*tables)
        return this
    }

    fun where(qbfParameters: QBFParameters): Select {
        this.qbfParameters = qbfParameters
        return this
    }

    fun ext(queryOperation: QueryOperation): Select {
        this.queryOperation = queryOperation
        return this
    }

    fun orderBy(column: String): Select {
        queryOperation.order(column)
        return this
    }

    fun orderBy(column: String, asc: Boolean): Select {
        queryOperation.order(column, asc)
        return this
    }

    fun page(pageNum: Int, pageSize: Int): Select {
        queryOperation.page(pageNum, pageSize)
        return this
    }

    fun groupBy(vararg value: String): Select {
        this.groups = arrayOf(*value)
        return this
    }

    fun having(qbfParameters: QBFParameters?): Select {
        this.having = qbfParameters
        return this
    }

    fun UNION(select: Select) {
        this.unionSelect = select
    }


    class Table {
        var tableName: String? = null
        var alise: String? = null
        var subSelect: Select? = null

        constructor(tableName: String?) {
            this.tableName = tableName
        }

        constructor(subSelect: Select?) {
            this.subSelect = subSelect
        }

        fun AS(alise: String?): Table {
            this.alise = alise
            return this
        }
    }

    //join
    fun join(table: String): Join {
        val join = Join(JOIN.InnerJOIN, table, this)
        joins.add(join)
        return join
    }

    fun leftJOIN(table: String): Join {
        val join = Join(JOIN.LeftJOIN, table, this)
        joins.add(join)
        return join
    }

    fun rightJOIN(table: String): Join {
        val join = Join(JOIN.RightJOIN, table, this)
        joins.add(join)
        return join
    }

    fun fullJOIN(table: String): Join {
        val join = Join(JOIN.FullJOIN, table, this)
        joins.add(join)
        return join
    }

    enum class JOIN(val _name:String) {
        LeftJOIN("LEFT JOIN"), RightJOIN("RIGHT JOIN"), FullJOIN("FULL JOIN"), InnerJOIN("INNER JOIN")
    }

    companion object {
        //------------>>
        fun c(vararg value: Any): Select {
            return Select(arrayOf(*value))
        }

        fun TABLE(tableName: String): Table {
            return Table(tableName)
        }

        fun TABLE(select: Select): Table {
            return Table(select)
        }

        //getSQL
        fun COUNT(): ColumnFunction<*> {
            return COUNT("*")
        }

        fun COUNT(columnName: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("COUNT", columnName) {}
        }

        fun COLUMN(columnName: String): ColumnFunction<*> {
            return object : ColumnFunction<Any>("column", columnName) {}
        }


        fun AVG(column: String): ColumnFunction<Number> {
            return object : ColumnFunction<Number>("AVG", column) {
            }
        }

        fun FIRST(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("FIRST", column) {
            }
        }

        fun LAST(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("LAST", column) {
            }
        }

        fun MAX(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("MAX", column) {
            }
        }

        fun MIN(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("MIN", column) {

            }
        }

        fun SUM(column: String): ColumnFunction<Number> {
            return object : ColumnFunction<Number>("SUM", column) {

            }
        }

        fun UCASE(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("UCASE", column) {

            }
        }

        fun LCASE(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("LCASE", column) {
            }
        }

        fun MID(column: String, start: Int): ColumnFunction<String> {
            return MIDFunction(column, start)
        }

        fun MID(column: String, start: Int, length: Int): ColumnFunction<String> {
            return MIDFunction(column, start, length)
        }


        fun LEN(column: String): ColumnFunction<String> {
            return object : ColumnFunction<String>("LEN", column) {
            }
        }

        fun ROUND(column: String, decimals: Int): ColumnFunction<String> {
            return ROUNDFunction(column, decimals)
        }

        @OptIn(ExperimentalTime::class)
        fun NOW(): ColumnFunction<Instant> {
            return object : ColumnFunction<Instant>("NOW") {
            }
        }

        fun FORMAT(column: String, format: String): ColumnFunction<String> {
            return FORMATFunction(column, format)
        }
    }
}
